﻿using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Cms.Application.Admin.Views;
using Cms.Application.IO;
using Cms.Data;
using Cms.Domain;
using Cms.Domain.RepositoryInterfaces;

namespace Cms.Application.Admin.Presenters
{
    public class EditMediaFilePresenter : BasePresenter
    {
        private readonly Administrator _administrator;
        private readonly IEditMediaFileView _view;

        public IDiskAccess DiskAccess { get; set; }

        public EditMediaFilePresenter(IEditMediaFileView view)
            : this(view, new RepositoryFactory())
        {
            DiskAccess = new DiskAccess();
        }
        
        public EditMediaFilePresenter(IEditMediaFileView view, IRepositoryFactory repositoryFactory)
            : base(view, repositoryFactory)
        {
            _view = view;
            _administrator = AdministratorRepository.GetAdministrator(_view.AdministratorID);
            if (!_administrator.HasPermission.EditMediaFile)
                _view.RedirectToPermissionDeniedPage();
        }

        public void UpdateLocales()
        {
            _view.SetLocales(_administrator.CurrentSite.Locales);
        }
        
        public void Initialize()
        {
            _view.SetFolders(_administrator.CurrentSite.Domain, _administrator.CurrentSite.GetRootMediaFolders());
            MediaFile file = MediaRepository.GetMediaFile(_view.FileID);
            _view.Name = file.Name;
            _view.SortKey = file.SortKey;
            if (file.Folder == null)
                _view.SelectedFolderID = -1;
            else
                _view.SelectedFolderID = file.Folder.ID;
            _view.SelectedLocaleID = _administrator.CurrentSiteLocale != null
                                         ? _administrator.CurrentSiteLocale.ID
                                         : _administrator.CurrentSite.DefaultLocale.ID;
            MediaFolder selectedFolder = MediaRepository.GetMediaFolder(_view.SelectedFolderID);
            IList<Category> selectedFolderCategories = selectedFolder != null
                                                           ? selectedFolder.Categories
                                                           : new List<Category>();
            _view.SetCategories(_administrator.CurrentSite.GetRootCategories(), selectedFolderCategories, file.Categories);
            IList<AdministratorGroup> folderAllowedAdministratorGroups = selectedFolder != null
                                                                             ? selectedFolder.GetAllAllowedAdministratorGroups()
                                                                             : new List<AdministratorGroup>();
            _view.SetAllowedAdministratorGroups(AdministratorRepository.GetCustomGroups(), folderAllowedAdministratorGroups, file.AllowedAdministratorGroups);
            IList<AdministratorGroup> folderDeniedAdministratorGroups = selectedFolder != null
                                                                            ? selectedFolder.GetAllDeniedAdministratorGroups()
                                                                            : new List<AdministratorGroup>();
            _view.SetDeniedAdministratorGroups(AdministratorRepository.GetCustomGroups(), folderDeniedAdministratorGroups, file.DeniedAdministratorGroups);
            IList<UserGroup> folderAllowedUserGroups = selectedFolder != null
                                                           ? selectedFolder.GetRequiredUserGroups()
                                                           : new List<UserGroup>();
            _view.SetRequiredUserGroups(UserRepository.GetUserGroups(), folderAllowedUserGroups, file.RequiredUserGroups, file.DeselectedUserGroups);
        }
        
        public void UpdateCategoriesAndGroups()
        {
            MediaFolder selectedFolder = MediaRepository.GetMediaFolder(_view.SelectedFolderID);
            IList<Category> selectedFolderCategories = selectedFolder != null
                                                           ? selectedFolder.Categories
                                                           : new List<Category>();
            _view.SetCategories(_administrator.CurrentSite.GetRootCategories(), selectedFolderCategories, _view.GetSelectedCategories().ToList());

            // Administrator groups
            IList<AdministratorGroup> folderAllowedAdministratorGroups = selectedFolder != null
                                                                             ? selectedFolder.GetAllAllowedAdministratorGroups()
                                                                             : new List<AdministratorGroup>();
            _view.SetAllowedAdministratorGroups(AdministratorRepository.GetCustomGroups(), folderAllowedAdministratorGroups, _view.GetSelectedAllowedAdministratorGroups().ToList());
            IList<AdministratorGroup> folderDeniedAdministratorGroups = selectedFolder != null
                                                                            ? selectedFolder.GetAllDeniedAdministratorGroups()
                                                                            : new List<AdministratorGroup>();
            _view.SetDeniedAdministratorGroups(AdministratorRepository.GetCustomGroups(), folderDeniedAdministratorGroups, _view.GetSelectedDeniedAdministratorGroups().ToList());

            // User groups
            IList<UserGroup> folderAllowedUserGroups = selectedFolder != null
                                                           ? selectedFolder.GetRequiredUserGroups()
                                                           : new List<UserGroup>();
            _view.SetRequiredUserGroups(
                UserRepository.GetUserGroups(), 
                folderAllowedUserGroups, 
                _view.GetSelectedRequiredUserGroups().ToList(),
                _view.GetDeselectedUserGroups().ToList());
        }
        
        public void RefreshProperties()
        {
            MediaFile file = MediaRepository.GetMediaFile(_view.FileID);
            _view.Name = file.Name;
            if (file.Folder == null)
                _view.SelectedFolderID = -1;
            else
                _view.SelectedFolderID = file.Folder.ID;
            _view.SortKey = file.SortKey;
            if (file.LocalizedProperties.ContainsKey(_view.SelectedLocaleID))
            {
                _view.FileTitle = file.LocalizedProperties[_view.SelectedLocaleID].Title;
                _view.FileDescription = file.LocalizedProperties[_view.SelectedLocaleID].Description;
            }
            else
            {
                _view.FileTitle = string.Empty;
                _view.FileDescription = string.Empty;
            }
            MediaFolder selectedFolder = MediaRepository.GetMediaFolder(_view.SelectedFolderID);
            IList<Category> selectedFolderCategories = selectedFolder != null
                                                           ? selectedFolder.Categories
                                                           : new List<Category>();
            _view.SetCategories(_administrator.CurrentSite.GetRootCategories(), selectedFolderCategories, file.Categories);
            IList<AdministratorGroup> folderAllowedAdministratorGroups = file.Folder != null
                                                                             ? file.Folder.GetAllAllowedAdministratorGroups()
                                                                             : new List<AdministratorGroup>();
            _view.SetAllowedAdministratorGroups(AdministratorRepository.GetCustomGroups(), folderAllowedAdministratorGroups, file.AllowedAdministratorGroups);
            IList<AdministratorGroup> folderDeniedAdministratorGroups = file.Folder != null
                                                                            ? file.Folder.GetAllDeniedAdministratorGroups()
                                                                            : new List<AdministratorGroup>();
            _view.SetDeniedAdministratorGroups(AdministratorRepository.GetCustomGroups(), folderDeniedAdministratorGroups, file.DeniedAdministratorGroups);
            IList<UserGroup> folderRequiredUserGroups = file.Folder != null
                                                            ? file.Folder.GetRequiredUserGroups()
                                                            : new List<UserGroup>();
            _view.SetRequiredUserGroups(UserRepository.GetUserGroups(), folderRequiredUserGroups, file.RequiredUserGroups, file.DeselectedUserGroups);
        }

        public void SaveSelectedLocale()
        {
            _administrator.CurrentSiteLocale = LocaleRepository.GetLocale(_view.SelectedLocaleID);
            AdministratorRepository.SaveAdministrator(_administrator);
        }
        
        public void Save()
        {
            if (_view.Name.Trim() == string.Empty)
            {
                AddValidationError(GetText(_view, "NoNameError"));
            }
            else if (!Regex.IsMatch(_view.Name, "^[a-zA-Z0-9-_]+(\\.[a-zA-Z0-9]+)+$"))
            {
                AddValidationError(GetText(_view, "InvalidNameError"));
            }
            if (!_administrator.CurrentSite.CanMediaFileBeNamedAndMovedTo(_view.FileID, _view.Name, MediaRepository.GetMediaFolder(_view.SelectedFolderID)))
            {
                AddValidationError(GetText(_view, "NameCollisionError"));
            }
            if (!IsValid)
            {
                return;
            }
            MediaFile file = MediaRepository.GetMediaFile(_view.FileID);
            string originalPhysicalPath = file.GetPhysicalPath();
            string originalVirtualPath = file.GetVirtualPath();
            file.Name = _view.Name;
            file.Extension = _view.Name.Substring(_view.Name.LastIndexOf(".") + 1);
            file.Folder = MediaRepository.GetMediaFolder(_view.SelectedFolderID);
            file.SortKey = _view.SortKey;
            foreach (Category category in file.Categories)
                category.MediaFiles.Remove(file);
            file.Categories.Clear();
            foreach (Category category in _view.GetSelectedCategories())
            {
                file.Categories.Add(category);
                category.MediaFiles.Add(file);
            }
            foreach (AdministratorGroup group in file.AllowedAdministratorGroups)
                group.AllowedMediaFiles.Remove(file);
            file.AllowedAdministratorGroups.Clear();
            foreach (AdministratorGroup group in _view.GetSelectedAllowedAdministratorGroups())
            {
                file.AllowedAdministratorGroups.Add(group);
                group.AllowedMediaFiles.Add(file);
            }
            foreach (AdministratorGroup group in file.DeniedAdministratorGroups)
                group.DeniedMediaFiles.Remove(file);
            file.DeniedAdministratorGroups.Clear();
            foreach (AdministratorGroup group in _view.GetSelectedDeniedAdministratorGroups())
            {
                file.DeniedAdministratorGroups.Add(group);
                group.DeniedMediaFiles.Add(file);
            }
            foreach (UserGroup group in file.RequiredUserGroups)
                group.SelectedMediaFiles.Remove(file);
            file.RequiredUserGroups.Clear();
            foreach (UserGroup group in _view.GetSelectedRequiredUserGroups())
            {
                file.RequiredUserGroups.Add(group);
                group.SelectedMediaFiles.Add(file);
            }
            foreach (UserGroup group in file.DeselectedUserGroups)
                group.DeselectedMediaFiles.Remove(file);
            file.DeselectedUserGroups.Clear();
            foreach (UserGroup group in _view.GetDeselectedUserGroups())
            {
                file.DeselectedUserGroups.Add(group);
                group.DeselectedMediaFiles.Add(file);
            }
            if (!file.LocalizedProperties.ContainsKey(_view.SelectedLocaleID))
                file.LocalizedProperties.Add(_view.SelectedLocaleID, new MediaFileLocalizedProperties());
            file.LocalizedProperties[_view.SelectedLocaleID].Title = _view.FileTitle;
            file.LocalizedProperties[_view.SelectedLocaleID].Description = _view.FileDescription;
            MediaRepository.SaveMediaFile(file);
            if (file.GetVirtualPath() != originalVirtualPath)
            {
                var frm = new FileReferencesManager(_administrator, SiteRepository, ContentRepository, DiskAccess);
                frm.UpdateFileReferences(originalVirtualPath, file.GetVirtualPath(), _administrator.CurrentSite.ID);
            }
            SiteRepository.SaveSite(_administrator.CurrentSite);
            DiskAccess.MoveFile(originalPhysicalPath, file.GetPhysicalPath());
            _administrator.SelectedMediaFolderID = file.Folder != null ? file.Folder.ID : -1;
            AdministratorRepository.SaveAdministrator(_administrator);
            _view.RemoveFileFromOutputCache(originalVirtualPath);
        }
        
        public bool IsInCategory(Category category)
        {
            MediaFile file = MediaRepository.GetMediaFile(_view.FileID);
            return category.ContainsMediaFile(file);
        }
        
        public bool IsInInheritedCategory(Category category)
        {
            MediaFile file = MediaRepository.GetMediaFile(_view.FileID);
            if (file == null)
                return false;
            return file.Folder != null && category.ContainsMediaFolder(file.Folder);
        }
    }
}